`include "global_def.h"

module Rasterisation(
  I_CLK, 
  I_RST_N,
  I_VIDEO_ON,
  I_Opcode,
	I_Fragment_x0,
	I_Fragment_x1,
	I_Fragment_x2,
	I_Fragment_x3,
	I_Fragment_x4,
	I_Fragment_x5,
	I_Fragment_x6,
	I_Fragment_x7,
	I_Fragment_x8,
	I_Fragment_y0,
	I_Fragment_y1,
	I_Fragment_y2,
	I_Fragment_y3,
	I_Fragment_y4,
	I_Fragment_y5,
	I_Fragment_y6,
	I_Fragment_y7,
	I_Fragment_y8,
  I_Color0,
  I_Color1,
  I_Color2,
  O_GPU_DATA,
  O_GPU_ADDR,
  O_RAST_STALL
);
input	I_CLK;
input I_RST_N;
input	I_VIDEO_ON;
input [15:0] I_Fragment_x0;
input [15:0] I_Fragment_x1;
input [15:0] I_Fragment_x2;
input [15:0] I_Fragment_x3;
input [15:0] I_Fragment_x4;
input [15:0] I_Fragment_x5;
input [15:0] I_Fragment_x6;
input [15:0] I_Fragment_x7;
input [15:0] I_Fragment_x8;
input [15:0] I_Fragment_y0;
input [15:0] I_Fragment_y1;
input [15:0] I_Fragment_y2;
input [15:0] I_Fragment_y3;
input [15:0] I_Fragment_y4;
input [15:0] I_Fragment_y5;
input [15:0] I_Fragment_y6;
input [15:0] I_Fragment_y7;
input [15:0] I_Fragment_y8;
input [15:0] I_Color0;
input [15:0] I_Color1;
input [15:0] I_Color2;
input [`OPCODE_WIDTH-1:0] I_Opcode;

output reg  [15:0] O_GPU_DATA;
output reg  [17:0] O_GPU_ADDR;
output reg O_RAST_STALL;

//Internal regs
reg [22:0]  rowInd;
reg [22:0]  colInd;

//Internal wires
wire [22:0] a[0:8];
wire [22:0] b[0:8];
wire [22:0] c[0:8];
wire [22:0] c_1[0:8];
wire [22:0] c_2[0:8];
//wire [15:0] min_x;
//wire [15:0] max_x;
//wire [15:0] min_y;
//wire [15:0] max_y;
wire inside[0:8];
wire [22:0] fragment_x[0:8];
wire [22:0] fragment_y[0:8];

genvar i;

initial begin
	O_RAST_STALL = 0;
end

assign fragment_x[0] = I_Fragment_x0;
assign fragment_x[1] = I_Fragment_x1;
assign fragment_x[2] = I_Fragment_x2;
assign fragment_x[3] = I_Fragment_x3;
assign fragment_x[4] = I_Fragment_x4;
assign fragment_x[5] = I_Fragment_x5;
assign fragment_x[6] = I_Fragment_x6;
assign fragment_x[7] = I_Fragment_x7;
assign fragment_x[8] = I_Fragment_x8;
assign fragment_y[0] = I_Fragment_y0;
assign fragment_y[1] = I_Fragment_y1;
assign fragment_y[2] = I_Fragment_y2;
assign fragment_y[3] = I_Fragment_y3;
assign fragment_y[4] = I_Fragment_y4;
assign fragment_y[5] = I_Fragment_y5;
assign fragment_y[6] = I_Fragment_y6;
assign fragment_y[7] = I_Fragment_y7;
assign fragment_y[8] = I_Fragment_y8;

//Traverse Setup
generate
	for (i=0; i<9; i=i+3)
	begin: abc_loop
		assign a[i] = fragment_y[2+i] - fragment_y[1+i];
		assign b[i] = fragment_x[1+i] - fragment_x[2+i];
		assign c_1[i] = -1 * a[i] * fragment_x[1+i];
		assign c_2[i] = -1 * b[i] * fragment_y[1+i];
		assign c[i] = c_1[i] + c_2[i];

		assign a[1+i] = fragment_y[i] - fragment_y[2+i];
		assign b[1+i] = fragment_x[2+i] - fragment_x[i];
		assign c_1[1+i] = -1 * a[1+i] * fragment_x[2+i];
		assign c_2[1+i] = -1 * b[1+i] * fragment_y[2+i];
		assign c[1+i] = c_1[1+i] + c_2[1+i];

		assign a[2+i] = fragment_y[1+i] - fragment_y[i];
		assign b[2+i] = fragment_x[i] - fragment_x[1+i];
		assign c_1[2+i] = -1 * a[2+i] * fragment_x[i];
		assign c_2[2+i] = -1 * b[2+i] * fragment_y[i];
		assign c[2+i] = c_1[2+i] + c_2[2+i];

		Inside i0(inside[i],colInd,rowInd,a[i],b[i],c[i]);
		Inside i1(inside[i+1],colInd,rowInd,a[i+1],b[i+1],c[i+1]);
		Inside i2(inside[i+2],colInd,rowInd,a[i+2],b[i+2],c[i+2]);
	end
endgenerate

always @(negedge I_CLK)
begin
	if (!I_VIDEO_ON && I_Opcode == `OP_DRAW) begin
		//O_RAST_STALL <= 1;
		O_GPU_ADDR <= rowInd*640 + colInd;
		if(inside[0] && inside[1] && inside[2])
			O_GPU_DATA <= I_Color0;
		else if(inside[3] && inside[4] && inside[5])
			O_GPU_DATA <= I_Color1;
//		else if(inside[6] && inside[7] && inside[8])
//			O_GPU_DATA <= I_Color2;
		else
			O_GPU_DATA <= {4'h0, 4'h0, 4'h0, 4'h0};
	end
end

always @(posedge I_CLK)
begin
    if (!I_VIDEO_ON && I_Opcode == `OP_DRAW) begin
      if (colInd < 639)
        colInd <= colInd + 1;
      else
        colInd <= 0;
    end
end

always @(posedge I_CLK)
begin
	if(I_Opcode == `OP_DRAW)
		O_RAST_STALL <= 1;
    if (!I_VIDEO_ON && I_Opcode == `OP_DRAW) begin
      if (colInd == 0) begin
        if (rowInd < 399)
          rowInd <= rowInd + 1;
        else begin
          rowInd <= 0;
			 O_RAST_STALL <= 0;
		  end
      end
    end
end

endmodule